package com.htwy.core.model;

import com.htwy.core.config.WebappConfig;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.ehcache.CacheKit;
import com.jfinal.plugin.ehcache.CacheName;
import java.util.Arrays;
import java.util.List;

public abstract class CacheModel<M extends CacheModel<M>> extends BaseModel<M> {

    private boolean usingCache = false;
    private String cacheName = null;

    protected String generateCacheKey(String method, SqlPara sqlPara){
        return generateCacheKey(method,sqlPara.getSql(),sqlPara.getPara());
    }

    protected String generateCacheKey(String method,String sql,Object... params){
        StringBuffer buffer = new StringBuffer();
        buffer.append(method);
        buffer.append("(");
        if (StrKit.notBlank(sql)) {
            buffer.append(sql);
        }
        if(params != null && params.length>0){
            for (Object param : params){
                buffer.append(",").append(param == null?"null":String.valueOf(param));
            }
        }
        buffer.append(")");
        return buffer.toString();
    }

    public CacheModel(){
        CacheName anno = getClass().getAnnotation(CacheName.class);
        if(anno != null){
            this.cacheName = anno.value();
        }else{
            this.cacheName = "";
        }
        usingCache = WebappConfig.isUseEhcache() && StrKit.notBlank(cacheName);
    }

    protected boolean isUsingCache(){
        return this.usingCache;
    }

    protected <T> T getCacheValue(String key){
        if(usingCache){
            return CacheKit.get(this.cacheName,key);
        }else{
            return null;
        }
    }

    protected void putCacheValue(String key, Object value){
        if(usingCache){
            CacheKit.put(this.cacheName,key,value);
        }
    }

    protected void clearCache(){
        if(usingCache){
            CacheKit.removeAll(this.cacheName);
        }
    }

    @Override
    public boolean save() {
        clearCache();
        return super.save();
    }

    @Override
    public boolean delete() {
        clearCache();
        return super.delete();
    }

    @Override
    public boolean deleteById(Object idValue) {
        clearCache();
        return super.deleteById(idValue);
    }

    @Override
    public boolean deleteById(Object... idValues) {
        clearCache();
        return super.deleteById(idValues);
    }

    @Override
    public boolean update() {
        clearCache();
        return super.update();
    }

    @Override
    public M findById(Object idValue) {
        if(usingCache){
            String cacheKey = generateCacheKey("findById",null,idValue);
            M result = getCacheValue(cacheKey);
            if (result == null) {
                result = super.findById(idValue);
                putCacheValue(cacheKey, result);
            }
            return result;
        }
        return super.findById(idValue);
    }

    @Override
    public M findById(Object... idValues) {
        if(usingCache){
            String cacheKey = generateCacheKey("findById",null,idValues);
            M result = getCacheValue(cacheKey);
            if (result == null) {
                result = super.findById(idValues);
                putCacheValue(cacheKey,result);
            }
            return result;
        }
        return super.findById(idValues);
    }

    @Override
    public List<M> find(SqlPara sqlPara) {
        return find(sqlPara, true);
    }

    public List<M> find(SqlPara sqlPara,Boolean useCache) {
        if(usingCache && useCache){
            String cacheKey = generateCacheKey("find",sqlPara);
            List<M> result = getCacheValue(cacheKey);
            if (result == null) {
                result = super.find(sqlPara);
                putCacheValue(cacheKey,result);
            }
            return result;
        }
        return super.find(sqlPara);
    }

    @Override
    public M findFirst(SqlPara sqlPara){
        return findFirst(sqlPara, true);
    }


    public M findFirst(SqlPara sqlPara, Boolean useCache) {
        if(usingCache && useCache){
            String cacheKey = generateCacheKey("findFirst",sqlPara);
            M result = getCacheValue(cacheKey);
            if (result == null) {
                result = super.findFirst(sqlPara);
                putCacheValue(cacheKey,result);
            }
            return result;
        }
        return super.findFirst(sqlPara);
    }

    @Override
    public Page<M> paginate(int pageNumber, int pageSize, SqlPara sqlPara) {
        return paginate(pageNumber, pageSize, sqlPara, true);
    }

    public Page<M> paginate(int pageNumber, int pageSize, SqlPara sqlPara, Boolean useCache) {
        if(usingCache && useCache){
            List params = Arrays.asList(sqlPara.getPara());
            params.add(pageNumber);
            params.add(pageSize);
            String cacheKey = generateCacheKey("paginate",sqlPara.getSql(),params.toArray());
            Page<M> result = getCacheValue(cacheKey);
            if (result == null) {
                result = super.paginate(pageNumber, pageSize, sqlPara);
                putCacheValue(cacheKey,result);
            }
            return result;
        }
        return super.paginate(pageNumber, pageSize, sqlPara);
    }
}
